#pragma once

#include<iostream>
#include<string>
#include<map>
#include<unordered_map>
#include<functional>
#include<fstream>

#include"Log.hpp"

namespace Http
{
    std::string homepage="index.html";//网页首页
    std::string wwwroot="wwwroot";//请求资源根目录
    std::string version="HTTP/1.0";//使用的HTTP版本
    std::string sep="\r\n";//换行符
    std::string sep_header=": ";//属性的键与键值之间的分隔符
    std::string sep_first_line=" ";//报头首行各个部分的分隔符
    std::string sep_arg_start="?";//URL中表示参数开始时的分隔符
    std::string sep_arg="&";//URL中参数之间的分隔符
    std::string sep_tail="#";//URL中表示片尾标识开始时的分隔符
    std::string sep_text="\r\n\r\n";//表示正文开始时的分割符分隔符
    std::string sep_suffix=".";//文件后缀分隔符


    //对一个完整的请求报文进行解析
    class Request
    {
    public:
    Request(std::string request)
    :_request(request)
    {
        Start();
    }

    bool IsExec()
    {
        return !_url_args.empty()||!_req_text.empty();
    }

    std::string GetMathod()
    {
        return _method;
    }

    std::string& GetVersion()
    {
        return _version;
    }

    std::string& GetPath()
    {
        return _url_path;
    }

    std::string& GetArgs()
    {
        return _url_args;
    }

    std::string& GetText()
    {
        return _req_text;
    }

    std::string& GetSuffix()
    {
        return _suffix;
    }

    ~Request()
    {}

    private:

    bool Start()
    {
        bool ret=true;
        if(ParseRequest())
        {
            Log(DEBUG,"Parse request successfully\n");
        }
        else
        {
            Log(ERROR,"Parse request unsuccessfully\n");
            return false;
        }

        if(ParseReqFirstLine())
        {
            Log(DEBUG,"Parse ReqFirstLine successfully\n");
        }
        else
        {
            Log(ERROR,"Parse ReqFirstLine unsuccessfully\n");
            return false;

        }

        if(!_req_headers.empty())
        {
            if(ParseReqHeaders())
            {
                Log(DEBUG,"Parse headers successfully\n");
            }
            else
            {
                for(auto e:_headers)
                {
                    printf("key: %s  value: %s\n",e.first.c_str(),e.second.c_str());
                }
                Log(ERROR,"Parse headers unsuccessfully\n");
                return false;
            }
        }

        if(ParseURL())
        {
            Log(DEBUG,"Parse URL successfully\n");
        }
        else
        {
            Log(ERROR,"Parse URL unsuccessfully\n");
            return false;
        }

        return true;
    }

    bool ParseRequest()
    {
        int pos=_request.find(sep);
        if(pos==std::string::npos)
        {
            return false;
        }
        _req_first_line=_request.substr(0,pos);
        _request.erase(0,pos+sep.size());

        pos=_request.find(sep_text);
        if(pos==std::string::npos)
        {
            return true;
        }
        _req_headers=_request.substr(0,pos+sep.size());
        _request.erase(0,pos+sep_text.size());

        _req_text=_request.substr(0,std::string::npos);

        return true;
    }

    bool ParseReqFirstLine()
    {
        int start=0;
        int end=_req_first_line.find(sep_first_line);
        if(std::string::npos==end)
        {
            return false;
        }
        _method=_req_first_line.substr(start,end-start);
        start=end+sep_first_line.size();
        end=_req_first_line.find(sep_first_line,start);
        if(std::string::npos==end)
        {
            return false;
        }
        _url=_req_first_line.substr(start,end-start);
        start=end+sep_first_line.size();
        _version=_req_first_line.substr(start,std::string::npos);
        if(_version.empty())
        {
            return false;
        }
        return true;
    }

    bool ParseReqHeaders()
    {
        int start=0;
        int end=0;
        while(true)
        {
            end=_req_headers.find(sep_header,start);
            if(std::string::npos==end)
            {
                return true;
            }
            std::string key=_req_headers.substr(start,end-start);
            start=end+sep_header.size();
            end=_req_headers.find(sep,start);
            if(std::string::npos==end)
            {
                return false;
            }
            std::string value=_req_headers.substr(start,end-start);
            start=end+sep.size();
            _headers.insert(std::pair<std::string,std::string>(key,value));
        }

        return false;
    }

    bool ParseURL()
    {
        int pos=_url.find("//");
        if(std::string::npos==pos)
        {
            pos=0;
        }
        int start=_url.find("/",pos);
        int end=_url.find(sep_arg_start,start);
        if(std::string::npos==start||start+1==_url.size())
        {
            _url_path+=wwwroot;
            _url_path+="/";
            _url_path+=homepage;
        }
        else
        {
            if(end==std::string::npos)
            {
                end=_url.find(sep_tail,start);
            }
            _url_path+=_url.substr(start+1,end-start-1);
            if(_url_path.empty())
            {
                _url_path+=wwwroot;
                _url_path+="/";
                _url_path+=homepage;
            }
        }

        start=_url_path.find(sep_suffix);
        if(std::string::npos==start||start+sep_suffix.size()>=_url_path.size())
        {
            _suffix="unknow";
        }
        else
        {
            _suffix=_url_path.substr(start+sep_suffix.size(),std::string::npos);
        }

        start=_url.find(sep_arg_start);
        if(std::string::npos!=start&&start+sep_arg_start.size()!=_url.size())
        {
            start+=sep_arg_start.size();
            end=_url.find(sep_tail);
            _url_args=_url.substr(start,end-start);
        }


        return true;
    }

    private:
    std::string _request;//一个完整的请求报文

    std::string _req_first_line;//报文首行
    std::string _req_headers;//报文属性列
    std::string _req_text;//报文正文

    std::string _method;//请求方法
    std::string _url;//URL
    std::string _version;//HTTP版本

    std::string _url_args;//URL参数
    std::string _url_path;//URL请求资源路径
    std::string _suffix;//URL请求资源文件后缀

    std::map<std::string,std::string> _headers;//报文属性列：键--键值

    };


    class Response
    {
    public:
    Response(std::string ver=version)
    :_version(ver)
    {}

    bool AddStatus(int code,std::string desc)
    {
        _code=code;
        _desc=desc;

        return true;
    }

    bool AddHeader(std::string key,std::string value)
    {
        auto ret=_headers.insert(std::pair<std::string,std::string>(key,value));
        return ret.second;
    }

    bool AddData(std::string& data)
    {
        _data=data;

        return true;
    }

    std::string Serialize()
    {
        std::string response;
        response+=_version;
        response+=sep_first_line;
        response+=std::to_string(_code);
        response+=sep_first_line;
        response+=_desc;
        response+=sep;
        for(auto e:_headers)
        {
            response+=e.first;
            response+=sep_header;
            response+=e.second;
            response+=sep;
        }

        response+=sep;
        response+=_data;

        return response;
    }

    ~Response()
    {}

    private:

    std::string _data;
    std::string _version;
    int _code;
    std::string _desc;
    std::map<std::string,std::string> _headers;
    };

    using func_t = std::function<Response(Request&)>;

    class HttpServer
    {
    public:
    HttpServer()
    {
        Init();
    }

    bool Init()
    {
        _mime_type.insert(std::make_pair("html", "text/html"));
        _mime_type.insert(std::make_pair("css", "text/css"));
        _mime_type.insert(std::make_pair("js", "application/x-javascript"));
        _mime_type.insert(std::make_pair("png", "image/png"));
        _mime_type.insert(std::make_pair("jpg", "image/jpeg"));
        _mime_type.insert(std::make_pair("unknow", "text/html"));

        _code_to_desc.insert(std::make_pair(100, "Continue"));
        _code_to_desc.insert(std::make_pair(200, "OK"));
        _code_to_desc.insert(std::make_pair(301, "Moved Permanently"));
        _code_to_desc.insert(std::make_pair(302, "Found"));
        _code_to_desc.insert(std::make_pair(404, "Not Found"));
        _code_to_desc.insert(std::make_pair(500, "Internal Server Error"));

        return true;
    }

    //函数注册
    bool RegistFunc(std::string key,func_t func)
    {
        auto ret= _funcs.insert(std::make_pair(key,func));
        return ret.second;
    }


    std::string ReadFile(std::string path)
    {
        Log(DEBUG,"path %s\n",path.c_str());//-------
        sleep(3);
        std::ifstream in(path,std::ios::binary);
        if(!in.is_open())
        {
            return std::string();
        }

        if (!in.is_open())
        {
            return std::string();
        }
        in.seekg(0, in.end);
        int filesize = in.tellg();
        in.seekg(0, in.beg);
        std::string content;
        content.resize(filesize);
        in.read((char *)content.c_str(), filesize);
        in.close();
        return content;
    }

    //核心函数，处理请求，返回应答
    std::string ServerHandler(std::string req)
    {
        Request request(req);
        // if(request.IsExec())
        // {
        //     auto response=_funcs[request.GetPath()](request);
        //     return response.Serialize();
        // }
        std::string data=ReadFile(request.GetPath());
        Response response(request.GetVersion());
        if(data.empty())
        {
            std::string error_message=ReadFile("wwwroot/error_path.html");
            response.AddStatus(404,_code_to_desc[404]);
            response.AddHeader("Content-Length",std::to_string(error_message.size()));
            response.AddHeader("Content-Type",_mime_type["html"]);
            response.AddData(error_message);
            return response.Serialize();
        }
        response.AddStatus(200,_code_to_desc[200]);
        response.AddHeader("Content-Length",std::to_string(data.size()));
        response.AddHeader("Content-Type",_mime_type[request.GetSuffix()]);
        response.AddData(data);
        return response.Serialize();
    }

    ~HttpServer()
    {}
    private:
    std::unordered_map<std::string, std::string> _mime_type;
    std::unordered_map<int, std::string> _code_to_desc;
    std::unordered_map<std::string, func_t> _funcs;
    };
}